# -*- coding: gbk -*-
import json
import os

from ScnsModuleUpdate import to_upper_camel, to_lower_camel, update, to_bsp_upper_camel, to_bsp_lower_camel, to_bsp, sort_modules, PN, PCN, PUN


def init_func(arg, is_bsp=False):
    name, need_enum, need_bsp, need_init, need_status, need_rd, need_result, need_interrupt, need_update_result, bsp_dir = arg
    s = ''
    s += 'void' if not need_status else (to_upper_camel(name) + 'Status')
    s += ' ' + (to_bsp_lower_camel(name) if +is_bsp else to_lower_camel(name)) + 'Init('
    s += 'void' if not need_enum else (to_upper_camel(name) + 'Enum' + ' ' + to_lower_camel(name[5:8]) + 'N')
    s += ')'
    return s


def post_init_func(arg, ):
    name, need_enum, need_bsp, need_init, need_status, need_rd, need_result, need_interrupt, need_update_result, bsp_dir = arg
    s = ''
    s += 'void' if not need_status else (to_upper_camel(name) + 'Status')
    s += ' ' + to_bsp_lower_camel(name) + 'PostInit('
    s += 'void' if not need_enum else (to_upper_camel(name) + 'Enum' + ' ' + to_lower_camel(name[5:8]) + 'N')
    s += ')'
    return s


def interrupt_func(arg):
    name, need_enum, need_bsp, need_init, need_status, need_rd, need_result, need_interrupt, need_update_result, bsp_dir = arg
    s = 'void'
    s += ' ' + to_lower_camel(name) + 'Interrupt('
    s += 'void' if not need_enum else (to_upper_camel(name) + 'Enum' + ' ' + to_lower_camel(name[5:8]) + 'N')
    s += ')'
    return s


def update_result_func(arg):
    name, need_enum, need_bsp, need_init, need_status, need_rd, need_result, need_interrupt, need_update_result, bsp_dir = arg
    s = 'void'
    s += ' ' + to_bsp_lower_camel(name) + 'ResultUpdate('
    s += 'void' if not need_enum else (to_upper_camel(name) + 'Enum' + ' ' + to_lower_camel(name[5:8]) + 'N')
    s += ')'
    return s


def call_update_result_func(arg):
    name, need_enum, need_bsp, need_init, need_status, need_rd, need_result, need_interrupt, need_update_result, bsp_dir = arg
    s = '    '
    s += ' ' + to_bsp_lower_camel(name) + 'ResultUpdate('
    s += '' if not need_enum else (to_lower_camel(name[5:8]) + 'N')
    s += ')'
    s += ';'
    return s


def call_init_func(arg):
    name, need_enum, need_bsp, need_init, need_status, need_rd, need_result, need_interrupt, need_update_result, bsp_dir = arg
    s = '    '
    if need_status:
        s += PN + 'Check(' + to_upper_camel(name) + 'Status' + ','
    s += to_bsp_lower_camel(name) + 'Init('
    s += '' if not need_enum else (to_lower_camel(name[5:8]) + 'N')
    s += ')'
    if need_status:
        s += ',' + name + '_STATUS_OK)'
    s += ';'
    return s


def call_post_init_func(arg):
    name, need_enum, need_bsp, need_init, need_status, need_rd, need_result, need_interrupt, need_update_result, bsp_dir = arg
    s = '    '
    if need_status:
        s += PN + 'Check(' + to_upper_camel(name) + 'Status' + ','
    s += to_bsp_lower_camel(name) + 'PostInit('
    s += '' if not need_enum else (to_lower_camel(name[5:8]) + 'N')
    s += ')'
    if need_status:
        s += ',' + name + '_STATUS_OK)'
    s += ';'
    return s


def enum_define(arg):
    name, need_enum, need_bsp, need_init, need_status, need_rd, need_result, need_interrupt, need_update_result, bsp_dir = arg
    s = 'typedef enum\n'
    s += '{\n'
    s += '    ' + name + '_1,\n'
    s += '    ' + name + '_MAX,\n'
    s += '}' + to_upper_camel(name) + 'Enum;' + '\n'
    return s


def do(arg):
    name, need_enum, need_bsp, need_init, need_status, need_rd, need_result, need_interrupt, need_update_result, bsp_dir = arg
    modules = sort_modules(json.loads(open(PN + 'Modules.json', 'rb').read()))
    modules[name] = {}
    modules = sort_modules(modules)
    with open(PN + 'Modules.json', 'w') as f:
        f.write(json.dumps(modules, indent=4))

    with open(to_upper_camel(name) + '.h', 'w') as f:
        f.write('#ifndef __' + name + '_H__\n')
        f.write('#define __' + name + '_H__\n')
        f.write('#include "' + PCN + 'Config.h"\n')
        f.write('#if defined(' + name + '_ENABLE)&&' + name + '_ENABLE==1\n')
        if need_bsp:
            f.write('#include "' + to_bsp_upper_camel(name) + '.h"\n')
            f.write('\n\n\n')

        f.write('#include "' + PCN + 'Ying.h"\n')
        f.write('\n\n\n')

        if need_status:
            f.write('typedef enum\n')
            f.write('{\n')
            f.write('    ' + name + '_STATUS_OK=' + PUN + '_YING_STATUS_OK,\n')
            f.write('    ' + name + '_STATUS_BSP_FAILED=' + PUN + '_YING_STATUS_BSP_FAILED,\n')
            f.write('    ' + name + '_STATUS_FAILED=' + PUN + '_YING_STATUS_FAILED,\n')
            f.write('    ' + name + '_STATUS_TIME_OUT=' + PUN + '_YING_STATUS_TIME_OUT,\n')
            f.write('}' + (to_upper_camel(name) + 'Status') + ';\n')
            f.write('\n\n\n')

        if need_result:
            f.write('typedef struct\n')
            f.write('{\n')
            f.write('    uint8 inited;\n')
            f.write('}' + to_upper_camel(name) + 'Result;\n\n')

            f.write('extern ' + to_upper_camel(name) + 'Result ' + to_lower_camel(name) + 'Result')
            if need_enum:
                f.write('[' + name + '_MAX' + ']')
            f.write(';\n')
            f.write('\n\n\n')

        if need_init:
            f.write('extern ' + init_func(arg) + ';\n')

        if need_result and need_interrupt:
            f.write('extern ' + interrupt_func(arg) + ';\n')

        f.write('\n\n\n')
        f.write('#endif\n')
        f.write('#endif\n')
    with open(to_upper_camel(name) + '.c', 'w') as f:
        f.write('#include "' + to_upper_camel(name) + ('.c' if need_bsp else '') + '.h"\n')
        f.write('#if defined(' + name + '_ENABLE)&&' + name + '_ENABLE==1\n')
        f.write('\n\n\n')

        if need_rd:
            f.write('static struct\n')
            f.write('{\n')
            f.write('    uint8 inited;\n')
            f.write('}rd')
            if need_enum:
                f.write('[' + name + '_MAX' + ']')
            f.write(';\n')
            f.write('\n\n\n')
        if need_result:
            f.write(to_upper_camel(name) + 'Result ' + to_lower_camel(name) + 'Result')
            if need_enum:
                f.write('[' + name + '_MAX' + ']')
            f.write(';\n')
            f.write('\n\n\n')
        if need_init:
            f.write(init_func(arg) + '\n')
            f.write('{\n')
            if need_enum:
                f.write('    ' + PUN + '_ASSERT_ON_RUN(' + to_lower_camel(name[5:8]) + 'N' + '<' + name + '_MAX' + ');\n')
            if need_bsp:
                f.write(call_init_func(arg) + '\n')
            f.write('\n\n\n')
            if need_bsp:
                f.write(call_post_init_func(arg) + '\n')
            if need_rd:
                f.write('    rd')
                if need_enum:
                    f.write('[' + to_lower_camel(name[5:8]) + 'N' + ']')
                f.write('.inited=1;\n')
            if need_status:
                f.write('    return ' + name + '_STATUS_OK;\n')
            f.write('}')
            f.write('\n\n\n')
        if need_result and need_interrupt:
            f.write(interrupt_func(arg) + '\n')
            f.write('{\n')
            if need_enum:
                f.write('    ' + PUN + '_ASSERT_ON_RUN(' + to_lower_camel(name[5:8]) + 'N' + '<' + name + '_MAX' + ');\n')
            if need_rd:
                f.write('    if(!rd')
                if need_enum:
                    f.write('[' + to_lower_camel(name[5:8]) + 'N' + ']')
                f.write('.inited)return;\n')
            f.write('\n\n\n')
            if need_update_result:
                f.write(call_update_result_func(arg) + '\n')
            f.write('}')
            f.write('\n\n\n')

        f.write('\n\n\n')
        f.write('#endif\n')

    if need_bsp:
        with open(to_upper_camel(name) + '.c.h', 'w') as f:
            f.write('#ifndef __' + name + '_C_H__\n')
            f.write('#define __' + name + '_C_H__\n')

            f.write('#include "' + to_upper_camel(name) + '.h"\n')
            f.write('#if defined(' + name + '_ENABLE)&&' + name + '_ENABLE==1\n')
            if need_bsp:
                f.write('#include "' + to_bsp_upper_camel(name) + '.c.h"\n')
            f.write('\n\n\n')

            if need_init:
                f.write('extern ' + init_func(arg, True) + ';\n')
                f.write('extern ' + post_init_func(arg) + ';\n')
            if need_result and need_interrupt and need_update_result:
                f.write('extern ' + update_result_func(arg) + ';\n')

            f.write('\n\n\n')

            f.write('/*******************************BSP.C.H*******************************\n')
            f.write('\n\n\n')
            f.write('*/\n')

            f.write('/*******************************BSP.H*******************************\n')
            if need_enum:
                f.write(enum_define(arg))
            f.write('\n\n\n')
            f.write('*/\n')

            f.write('\n\n\n')
            f.write('#endif\n')
            f.write('#endif\n')

            # BSPPPPPPPPPPPPPPPPPPPP
            with open(bsp_dir + to_bsp_upper_camel(name) + '.h', 'w') as f:
                f.write('#ifndef __' + to_bsp(name) + '_H__\n')
                f.write('#define __' + to_bsp(name) + '_H__\n')
                f.write('#include "' + PCN + 'Config.h"\n')
                f.write('#if defined(' + name + '_ENABLE)&&' + name + '_ENABLE==1\n')
                f.write('#include "' + PCN + 'Ying.h"\n')
                f.write('\n\n\n')

                if need_enum:
                    f.write(enum_define(arg))

                f.write('\n\n\n')
                f.write('#endif\n')
                f.write('#endif\n')
            with open(bsp_dir + to_bsp_upper_camel(name) + '.c', 'w') as f:
                f.write('#include "' + to_upper_camel(name) + '.c.h"\n')
                f.write('#if defined(' + name + '_ENABLE)&&' + name + '_ENABLE==1\n')
                f.write('\n\n\n')
                if need_init:
                    f.write(init_func(arg, is_bsp=True) + '\n')
                    f.write('{\n')
                    f.write('\n\n\n')
                    if need_status:
                        f.write('    return ' + name + '_STATUS_OK;\n')
                    f.write('}')
                    f.write('\n\n\n')

                    f.write(post_init_func(arg) + '\n')
                    f.write('{\n')
                    f.write('\n\n\n')
                    if need_status:
                        f.write('    return ' + name + '_STATUS_OK;\n')
                    f.write('}')
                    f.write('\n\n\n')

                if need_result and need_interrupt and need_update_result:
                    f.write(update_result_func(arg) + '\n')
                    f.write('{\n')
                    f.write('\n\n\n')
                    f.write('}')
                    f.write('\n\n\n')

                f.write('\n\n\n')
                f.write('#endif\n')
            with open(bsp_dir + to_bsp_upper_camel(name) + '.c.h', 'w') as f:
                f.write('#ifndef __' + to_bsp(name) + '_C_H__\n')
                f.write('#define __' + to_bsp(name) + '_C_H__\n')

                f.write('#include "' + to_upper_camel(name) + '.h"\n')
                f.write('#if defined(' + name + '_ENABLE)&&' + name + '_ENABLE==1\n')
                f.write('\n\n\n')

                f.write('\n\n\n')
                f.write('#endif\n')
                f.write('#endif\n')

    update()


def get_bsp_dirs():
    l = []
    for path, dir_list, file_list in os.walk(r'../' + PN + 'Bsp'):
        for dir_name in dir_list:
            path_name = os.path.join(path, dir_name, PCN + 'BspConfig.h')
            if os.path.exists(path_name):
                l.append(os.path.join(path, dir_name))
    return l


def get():
    name = PUN + '_' + input('name:').upper()
    need_enum = input('need_enum          (Y/N):').upper() == 'Y'
    need_bsp = input('need_bsp           (Y/N):').upper() == 'Y'
    need_init = input('need_init          (Y/N):').upper() == 'Y'
    need_status = input('need_status        (Y/N):').upper() == 'Y'
    need_rd = input('need_rd            (Y/N):').upper() == 'Y'
    need_result = input('need_result        (Y/N):').upper() == 'Y'
    need_interrupt = (input('need_interrupt     (Y/N):').upper() == 'Y') if need_result else False
    need_update_result = (input('need_update_result (Y/N):').upper() == 'Y') if need_interrupt else False

    bsp_dir = ''
    if need_bsp:
        L = get_bsp_dirs()
        for k, l in enumerate(L):
            print('%-3d %s' % (k, l))
        n = int(input('chose one (0,1,2,3...):'))
        bsp_dir = (L[n] + '/') if n < len(L) else '../' + PN + 'Bsp/'
        print(bsp_dir)

    print(name, to_upper_camel(name))
    print('need_enum         ', need_enum)
    print('need_bsp          ', need_bsp)
    print('need_init         ', need_init)
    print('need_status       ', need_status)
    print('need_rd           ', need_rd)
    print('need_result       ', need_result)
    print('need_interrupt    ', need_interrupt)
    print('need_update_result', need_update_result)
    print('bsp_dir           ', bsp_dir)

    if input('confirm        (Y/N):').upper() != 'Y':
        exit()
    return name, need_enum, need_bsp, need_init, need_status, need_rd, need_result, need_interrupt, need_update_result, bsp_dir


def fake_get():
    name = PUN + '_AAAA'
    need_enum = True
    need_bsp = True
    need_init = True
    need_status = True
    need_rd = True
    need_result = True
    need_interrupt = True
    need_update_result = True
    bsp_dir = '../' + PN + 'Bsp/'
    return name, need_enum, need_bsp, need_init, need_status, need_rd, need_result, need_interrupt, need_update_result, bsp_dir


if __name__ == '__main__':
    do(get())
    # do(fake_get())
